﻿using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Threading;

namespace O1.IO.Storage
{
    [ContractVerification(true)]
    public abstract class TransactionLog
    {
        private long lockValue;

        public void WriteToLog(byte[] data)
        {
            this.Synchronize();
            this.Write(data);
        }

        public void CommitEntry()
        {
            this.Commit(Markup.CommittedVertex);
            this.Release();
        }

        public void InvalidateEntry()
        {
            this.Invalidate(Markup.UncommittedVertex);
            this.Release();
        }

        protected abstract void Write(byte[] data);

        protected abstract void Commit(byte marker);

        protected abstract void Invalidate(byte marker);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void Release()
        {
            this.lockValue = 0;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void Synchronize()
        {
            if (Interlocked.CompareExchange(ref this.lockValue, 1, 0) != 0)
            {
                var wait = new SpinWait();
                while (Interlocked.CompareExchange(ref this.lockValue, 1, 0) != 0)
                {
                    wait.SpinOnce();
                }
            }
        }
    }
}
